<!doctype html>
<html lang="en" class="page-type-section">
<head prefix="og: http://ogp.me/ns#">
<meta charset="utf-8">
<title>2.3.22 - FreeMarker 手册</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="format-detection" content="telephone=no">
<meta property="og:site_name" content="FreeMarker 手册">
<meta property="og:title" content="2.3.22">
<meta property="og:locale" content="en_US">
<meta property="og:url" content="http://freemarker.org/docs/versions_2_3_22.html">
<link rel="canoical" href="http://freemarker.org/docs/versions_2_3_22.html">
<link rel="icon" href="favicon.png" type="image/png">
<link rel="stylesheet" type="text/css" href="docgen-resources/docgen.min.css">
</head>
<body itemscope itemtype="https://schema.org/Code">
    <meta itemprop="url" content="http://freemarker.org/docs/">
    <meta itemprop="name" content="FreeMarker 手册">

  <!--[if lte IE 9]>
  <div style="background-color: #C00; color: #fff; padding: 12px 24px;">Please use a modern browser to view this website.</div>
  <![endif]--><div class="header-top-bg"><div class="site-width header-top"><a class="logo" href="http://freemarker.org" role="banner">            <img itemprop="image" src="logo.png" alt="FreeMarker">
</a><ul class="tabs"><li><a href="http://freemarker.org/">Home</a></li><li class="current"><a href="index.html">Manual</a></li><li><a class="external" href="http://freemarker.org/docs/api/index.html">Java API</a></li></ul><ul class="secondary-tabs"><li><a class="tab icon-heart" href="http://freemarker.org/contribute.html" title="Contribute"><span>Contribute</span></a></li><li><a class="tab icon-bug" href="https://sourceforge.net/p/freemarker/bugs/new/" title="Report a Bug"><span>Report a Bug</span></a></li><li><a class="tab icon-download" href="http://freemarker.org/freemarkerdownload.html" title="Download"><span>Download</span></a></li></ul></div></div><div class="header-bottom-bg"><div class="site-width search-row"><a href="toc.html" class="navigation-header">Manual</a><div class="navigation-header"></div></div><div class="site-width breadcrumb-row"><ul class="breadcrumb" itemscope itemtype="http://schema.org/BreadcrumbList"><li class="step-0" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="toc.html"><span itemprop="name">FreeMarker 手册</span></a></li><li class="step-1" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="app.html"><span itemprop="name">附录</span></a></li><li class="step-2" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="app_versions.html"><span itemprop="name">版本历史</span></a></li><li class="step-3" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="versions_2_3_22.html"><span itemprop="name">2.3.22</span></a></li></ul><div class="bookmarks" title="Bookmarks"><span class="sr-only">Bookmarks:</span><ul class="bookmark-list"><li><a href="alphaidx.html">Alpha. index</a></li><li><a href="gloss.html">Glossary</a></li><li><a href="dgui_template_exp.html#exp_cheatsheet">Expressions</a></li><li><a href="ref_builtins_alphaidx.html">?builtins</a></li><li><a href="ref_directive_alphaidx.html">#directives</a></li><li><a href="ref_specvar.html">.spec_vars</a></li><li><a href="app_faq.html">FAQ</a></li></ul></div></div></div>    <div class="main-content site-width">
      <div class="content-wrapper">
  <div id="table-of-contents-wrapper" class="col-left">
      <script>var breadcrumb = ["FreeMarker 手册","附录","版本历史","2.3.22"];</script>
      <script src="toc.js"></script>
      <script src="docgen-resources/main.min.js"></script>
  </div>
<div class="col-right"><div class="page-content"><div class="page-title"><div class="pagers top"><a class="paging-arrow previous" href="versions_2_3_23.html"><span>Previous</span></a><a class="paging-arrow next" href="versions_2_3_21.html"><span>Next</span></a></div><div class="title-wrapper">
<h1 class="content-header header-section1" id="versions_2_3_22" itemprop="headline">2.3.22</h1>
</div></div><div class="page-menu">
<div class="page-menu-title">Page Contents</div>
<ul><li><a class="page-menu-link" href="#autoid_148" data-menu-target="autoid_148">Changes on the FTL side</a></li><li><a class="page-menu-link" href="#autoid_149" data-menu-target="autoid_149">Changes on the Java side</a></li><li><a class="page-menu-link" href="#autoid_150" data-menu-target="autoid_150">Notes</a></li></ul> </div><p>Date of release: 2015-03-01</p><p>Note that since 2.3.22 is designed to be fully backward
        compatible with the previous 2.3.x releases, <em>some of the
        improvements and fixes described below are only activated when you
        specifically ask for 2.3.22 "incompatible
        improvements"</em> (it&#39;s always clearly indicated),
        because they could, with very small chance, break existing
        applications. For actively maintained applications it&#39;s probably
        better to allow them. See <a href="pgui_config_incompatible_improvements.html#pgui_config_incompatible_improvements_how_to_set">how to set
        "incomplatible improvements" here</a>.</p>
          



<h2 class="content-header header-section2" id="autoid_148">Changes on the FTL side</h2>


          <ul>
            <li>
              <p>New built-ins: <code class="inline-code">api</code> and
              <code class="inline-code">has_api</code>.
              <code class="inline-code"><em class="code-color">value</em>?api</code> provides
              access to the API (usually, the Java API) of
              <code class="inline-code"><em class="code-color">value</em></code>, like
              <code class="inline-code"><em class="code-color">value</em>?api.<em class="code-color">someJavaMethod()</em></code>,
              if the value itself supports this extra feature. This meant to
              be used rarely, when you need to call a Java method of an
              object, but the by-design simplistic view of the value that
              FreeMarker exposes to the templates hides that, and there&#39;s no
              equivalent built-in either. For example, when you put a
              <code class="inline-code">Map</code> into the data-model (and you are using
              the default object wrapper), <code class="inline-code">myMap.myMethod()</code>
              in a template basically translates to <code class="inline-code">((Method)
              myMap.get(&quot;myMethod&quot;)).invoke(...)</code> in Java, thus you
              can&#39;t call <code class="inline-code">myMethod</code>. If, however, you write
              <code class="inline-code">myMap?api.myMethod()</code> instead, that means
              <code class="inline-code">myMap.myMethod()</code> in Java.</p>

              <p><em>If you can, rely on the capabilities of the FTL
              types and the related built-ins as far as possible. Using
              <code class="inline-code">?api</code> is only the last
              resort.</em></p>

              <p>Using <code class="inline-code">?api</code> also happens to offer a
              workaround for the lack of non-<code class="inline-code">String</code>
              <code class="inline-code">Map</code> key support in FTL&#39;s
              <code class="inline-code">[]</code> operator (as in
              <code class="inline-code">myMap[key]</code>), because now you can write
              <code class="inline-code">myMap?api.get(nonStringKey)</code>.</p>

              <p><code class="inline-code">?api</code> is not enabled by default and
              isn&#39;t available for all values. <a href="ref_builtins_expert.html#ref_buitin_api_and_has_api">See more
              here...</a></p>
            </li>

            <li>
              <p>Identifiers (like <code class="inline-code">someVariable</code>) can now
              contain minus (<code class="inline-code">-</code>), dot
              (<code class="inline-code">.</code>), and colon (<code class="inline-code">:</code>) at any
              position, but those characters <em>must be escaped with a
              preceding backslash</em> (<code class="inline-code">\</code>), or else
              they would be interpreted as operators. For example, to read the
              variable whose name is "data-id", the correct
              expression is <code class="inline-code">data\-id</code>, as
              <code class="inline-code">data-id</code> would be interpreted as "data
              minus id". This also works for named macro parameters,
              which is useful when you want to accept arbitrary HTML
              attributes in a catch-all parameter, like in <code class="inline-code">&lt;@box
              class=&quot;someCssClass&quot; data\-id=product.id /&gt;</code>. (When
              you enumerate the catch-all parameter names inside the macro,
              the key string you get is <code class="inline-code">&quot;data-id&quot;</code> without
              <code class="inline-code">\</code> of course.)</p>
            </li>

            <li>
              <p>Added <code class="inline-code">?lower_abc</code> and
              <code class="inline-code">?upper_abc</code>. This converts
              <code class="inline-code">1</code>, <code class="inline-code">2</code>,
              <code class="inline-code">3</code>, etc., to the string
              <code class="inline-code">&quot;a&quot;</code>, <code class="inline-code">&quot;b&quot;</code>,
              <code class="inline-code">&quot;c&quot;</code>, etc. (or for <code class="inline-code">&quot;A&quot;</code>,
              <code class="inline-code">&quot;B&quot;</code>, <code class="inline-code">&quot;C&quot;</code>, etc.). When
              reaching <code class="inline-code">&quot;z&quot;</code>, it continues like
              <code class="inline-code">&quot;aa&quot;</code>, <code class="inline-code">&quot;ab&quot;</code>, etc. This is
              the same logic that you can see in column labels in spreadsheet
              applications (like Excel or Calc). <a href="ref_builtins_number.html#ref_builtin_lower_abc">More details...</a></p>
            </li>

            <li>
              <p>Added <code class="inline-code">?keep_before_last</code> and
              <code class="inline-code">?keep_after_last</code>. Example:
              <code class="inline-code">&quot;foo.bar.txt&quot;?keep_before_last(&quot;.&quot;)</code> returns
              <code class="inline-code">&quot;foo.bar&quot;</code>,
              <code class="inline-code">&quot;foo.bar.txt&quot;?keep_after_last(&quot;.&quot;)</code> returns
              <code class="inline-code">&quot;txt&quot;</code>. (These work like
              <code class="inline-code">?keep_before</code> and
              <code class="inline-code">?keep_after</code>, but those look for the first
              occurrence of the separator.)</p>
            </li>

            <li>
              <p>Added many missing UNICODE letters and digits to the set
              of legal identifier characters, like Korean letters (bug fixed:
              [<a href="https://sourceforge.net/p/freemarker/bugs/129/">129</a>])</p>
            </li>

            <li>
              <p>Error message quality improvements:</p>

              <ul>
                <li>
                  <p>Several improvements when calling custom JSP tags; see
                  them in its own section later.</p>
                </li>

                <li>
                  <p>Bug fixed: When localized lookup or template
                  acquisition has kicked in, error messages have still quoted
                  the name used for requesting the template, rather that the
                  actual template source name (like <code class="inline-code">foo.ftl</code>
                  instead of <code class="inline-code">foo_en.ftl</code>, when the template
                  was get as <code class="inline-code">foo.ftl</code>, but behind the scenes
                  was loaded from <code class="inline-code">foo_en.ftl</code>).</p>
                </li>

                <li>
                  <p>"Template not found" errors are now more
                  detailed, giving hints about accidentally using
                  <code class="inline-code">\</code> instead of <code class="inline-code">/</code>, or
                  backing out of the <code class="inline-code">TemplateLoader</code>&#39;s root
                  directory.</p>
                </li>

                <li>
                  <p>The <code class="inline-code">#setting</code> directive gives more
                  helpful error message when the setting name is not
                  recognized, and lists the allowed setting names or a
                  correction suggestion.</p>
                </li>

                <li>
                  <p>When a bad special variable name
                  (<code class="inline-code">.<em class="code-color">name</em></code>) is
                  encountered, the list of available names is shown in the
                  error message.</p>
                </li>

                <li>
                  <p>When <code class="inline-code">Map.get</code> or
                  <code class="inline-code">Map.containsKey</code> of a wrapped
                  <code class="inline-code">Map</code> throws a
                  <code class="inline-code">ClassCastException</code> or
                  <code class="inline-code">NullPointerException</code>, the error will
                  point to the causing FTL expression (with some explanation),
                  rather than bubbling up as low level runtime error.</p>
                </li>
              </ul>
            </li>
          </ul>
        
          



<h2 class="content-header header-section2" id="autoid_149">Changes on the Java side</h2>


          <ul>
            <li>
              <p>Object wrapping improvements:</p>

              <ul>
                <li>
                  <p><code class="inline-code">DefaultObjectWrapper</code>, only with its
                  <code class="inline-code">incompatible_improvements</code> set to 2.3.22
                  (<a href="pgui_datamodel_objectWrapper.html#topic.defaultObjectWrapperIcI">see how
                  here...</a>), or more precisely, with its new
                  <code class="inline-code">useAdaptersForContainers</code> setting set to
                  <code class="inline-code">true</code> (which defaults to
                  <code class="inline-code">true</code> when
                  <code class="inline-code">incompatible_improvements</code> is set to
                  2.3.22): It doesn&#39;t copy <code class="inline-code">Map</code>-s,
                  <code class="inline-code">List</code>-s, and arrays anymore when wrapping
                  them into <code class="inline-code">TemplateModel</code>-s (which is the
                  interface through with templates access all values), just
                  wraps them into thin <code class="inline-code">TemplateModel</code>
                  adapters, that will reach the original object for all
                  operations. The wrapped values will be instances of the new
                  <code class="inline-code">DefaultMapAdapter</code>,
                  <code class="inline-code">DefaultListAdapter</code> and
                  <code class="inline-code">DefaultArrayAdapter</code> classes, instead of
                  the legacy (copying) <code class="inline-code">SimpleHash</code> and
                  <code class="inline-code">SimpleSequence</code> classes. (Note that many
                  projects use pure <code class="inline-code">BeansWrapper</code> instead of
                  <code class="inline-code">DefaultObjectWrapper</code>, which has always
                  used the adapter approach, albeit a different implementation
                  of it. As the shortcomings of
                  <code class="inline-code">DefaultObjectWrapper</code> are fixed now, it&#39;s
                  always recommended over <code class="inline-code">BeansWrapper</code>, as
                  <code class="inline-code">BeansWrapper</code> gives quite confusing
                  multi-typed values and is substantially slower.)</p>

                  <p>While keeping backward compatibility as much as
                  possible was an important factor in this change, this is a
                  quite deep change, so you may want to <a href="#topic.defaultObjectWrapperSwitchToAdapters">review
                  the consequences and reasons here...</a> (But again, this
                  change is <em>not</em> active by default, so
                  merely updating FreeMarker wont risk the stability of
                  existing applications)</p>
                </li>

                <li>
                  <p>Added <code class="inline-code">TemplateMethodModelEx
                  BeansWrapper.wrap(Object object, Method method)</code>
                  for wrapping methods without wrapping their parent object
                  and without going through overloaded method selection on
                  invocation time.</p>
                </li>

                <li>
                  <p>Bug fixed [<a href="http://sourceforge.net/p/freemarker/bugs/372/">372</a>]:
                  <code class="inline-code">ClassCastException</code> when a
                  <code class="inline-code">SortedMap</code> (typically, a
                  <code class="inline-code">TreeMap</code>) is wrapped with
                  <code class="inline-code">DefaultObjectWrapper</code> and then a 1
                  character long string is get from it that doesn&#39;t exist. To
                  fix the issue, if the wrapped <code class="inline-code">Map</code> is a
                  <code class="inline-code">SortedMap</code> and it&#39;s wrapped by
                  <code class="inline-code">DefaultObjectWrapper</code>, it won&#39;t try to
                  fall back to a <code class="inline-code">Character</code> key after with
                  the <code class="inline-code">String</code> key has got
                  <code class="inline-code">null</code>. (This change should be backward
                  compatible, because when a <code class="inline-code">SortedMap</code> has
                  <code class="inline-code">Character</code> keys, the initial attempt with
                  <code class="inline-code">String</code> key causes
                  <code class="inline-code">ClassCastException</code>, thus, such
                  <code class="inline-code">SortedMap</code>-s were never usable as FTL
                  hashes.)</p>
                </li>

                <li>
                  <p>Bug fixed [<a href="http://sourceforge.net/p/freemarker/bugs/368/">368</a>]:
                  Only with <code class="inline-code">incompatible_improvements</code> set
                  to 2.3.22 or with its new
                  <code class="inline-code">useAdaptersForContainers</code> setting set to
                  <code class="inline-code">true</code>: Key order and other behavioral
                  peculiarities of "custom"
                  <code class="inline-code">Map</code> types isn&#39;t lost anymore. The same
                  stands for <code class="inline-code">List</code>-s too.</p>
                </li>

                <li>
                  <p>Added new setting,
                  <code class="inline-code">forceLegacyNonListCollections</code>. This only
                  matters when <code class="inline-code">useAdaptersForContainers</code> is
                  <code class="inline-code">true</code>. Then, unless you set this to
                  <code class="inline-code">true</code>,
                  <code class="inline-code">java.util.Collection</code>-s that aren&#39;t
                  <code class="inline-code">List</code>-s (like <code class="inline-code">Set</code>-s)
                  will continue using <code class="inline-code">SimpleSequence</code> (i.e.,
                  the copying approach) instead of the adapter approach. The
                  default is <code class="inline-code">false</code>, at least until
                  <code class="inline-code">incompatible_improvements</code> 2.4.0, because
                  <code class="inline-code">SimpleSequence</code> gave indexed access to
                  these non-<code class="inline-code">List</code>-s, like in
                  <code class="inline-code">mySet[2]</code>, which is strange but some
                  existing templates may utilize this, even if only
                  accidentally. With
                  <code class="inline-code">forceLegacyNonListCollections</code> set to
                  <code class="inline-code">false</code>, indexed access won&#39;t be possible
                  for <code class="inline-code">Set</code>-s and such anymore (nor will
                  <code class="inline-code">?first</code> and <code class="inline-code">?last</code> work,
                  but <code class="inline-code">?size</code> will still do), so you may want
                  to retest old templates. On the other hand, you get the
                  advantages of the adapter approach. Hence, in new projects
                  it&#39;s highly recommended to set
                  <code class="inline-code">forceLegacyNonListCollections</code> to
                  <code class="inline-code">false</code>. (The adapter approach is
                  implemented by
                  <code class="inline-code">DefaultNonListCollectionAdapter</code>.)</p>
                </li>

                <li>
                  <p>Added new, <em>experimental</em> FTL type
                  interface,
                  <code class="inline-code">freemarker.template.TemplateCollectionModelEx</code>,
                  which adds the <code class="inline-code">size()</code>,
                  <code class="inline-code">isEmpty()</code>, and <code class="inline-code">boolean
                  contains(TemplateModel)</code> methods to the
                  <code class="inline-code">TemplateCollectionModel</code> interface. This
                  was added because when wrapping
                  <code class="inline-code">java.util.Collections</code> these extra
                  capabilities area available anyway, but FTL couldn&#39;t tap on
                  them till now. While the exact interface details are marked
                  as experimental, the feature itself is already utilized for
                  <code class="inline-code">?size</code> when setting the
                  <code class="inline-code">forceLegacyNonListCollections</code> property of
                  <code class="inline-code">DefaultObjectWrapper</code> to
                  <code class="inline-code">false</code> (see earlier).</p>
                </li>

                <li>
                  <p>Added new <em>experimental</em> interface,
                  <code class="inline-code">freemarker.template.ObjectWrapperAndUnwrapper</code>.
                  This extends <code class="inline-code">ObjectWrapper</code> with
                  unwrapping functionality. This functionality has already
                  existed for a long time in <code class="inline-code">BeansWrapper</code>
                  and its subclasses, like in
                  <code class="inline-code">DefaultObjectWrapper</code>, but it wasn&#39;t
                  "factored out" into its own published interface
                  that other <code class="inline-code">ObjectWrapper</code>-s could
                  implement. This is useful for
                  <code class="inline-code">TemplateModel</code> implementations that don&#39;t
                  want to require a <code class="inline-code">BeansWrapper</code> (or its
                  subclass), only the availability of the unwrapping
                  functionality.</p>
                </li>

                <li>
                  <p>Added new <em>experimental</em> interfaces
                  to implement <code class="inline-code">?api</code> (see it in the FTL
                  section): <code class="inline-code">TemplateModelWithAPISupport</code>,
                  <code class="inline-code">ObjectAPIWrapper</code>,
                  <code class="inline-code">RichObjectWrapper</code>. Note that while the
                  interfaces are experimental, <code class="inline-code">?api</code> itself
                  isn&#39;t.</p>
                </li>
              </ul>
            </li>

            <li>
              <p><code class="inline-code">FreemarkerServlet</code> improvements:</p>

              <ul>
                <li>
                  <p><code class="inline-code">FreemarkerServlet</code> now supports
                  custom JSP EL functions (defined in TLD-s with
                  <code class="inline-code">function</code> XML elements). Earlier it has
                  ignored them. The custom EL function can be called like a
                  Java method, for example: <code class="inline-code">&lt;#assign
                  u=JspTaglibs[&quot;/WEB-INF/utils.tld&quot;]&gt; ...
                  ${u.truncate(title, 25)}</code>.</p>
                </li>

                <li>
                  <p>Bug fixed: Error message was unhelpful when there was
                  a type mismatch between the actual and the expected type of
                  a custom tag parameter. This was a very frequent problem of
                  users who call JSP taglibs from FTL (the typical
                  &quot;java.lang.IllegalArgumentException: argument type
                  mismatch&quot;, without any FTL context). Now it&#39;s a proper error
                  with explanation, solution tip, and FTL error
                  position/quotation.</p>
                </li>

                <li>
                  <p>RFE resolved [<a href="https://sourceforge.net/p/freemarker/feature-requests/113/">113</a>]
                  [<a href="https://sourceforge.net/p/freemarker/feature-requests/114/">114</a>]:
                  <code class="inline-code">FreemarkerServlet</code> can now discover
                  <code class="inline-code">META-INF/**/*.tld</code>-s that are visible for
                  the class loader but aren&#39;t in
                  <code class="inline-code">WEB-INF/lib/*.jar</code>-s. For this feature to
                  be active, you must setup the extra TLD lookup with the
                  <code class="inline-code">MetaInfTldSources</code> and/or
                  <code class="inline-code">ClasspathTlds</code>
                  <code class="inline-code">FreemarkerServlet</code> init-params (see the
                  <a href="http://freemarker.org/docs/api/freemarker/ext/servlet/FreemarkerServlet.html">Java
                  API documentation of
                  <code>FreemarkerServlet</code></a> for the
                  description of these). For example, if you run your
                  application from Eclipse with an embedded Servlet container,
                  and thus the tag library jar-s aren&#39;t on the standard
                  locations but are in the classpath like any other
                  dependencies, now you can just write:</p>

                  

<div class="code-wrapper"><pre class="code-block code-unspecified">&lt;init-param&gt;
  &lt;param-name&gt;MetaInfTldSources&lt;/param-name&gt;
  &lt;param-value&gt;classpath&lt;/param-value&gt;
&lt;/init-param&gt;</pre></div>

                  <p>and then all the <code class="inline-code">META-INF</code>
                  directories that are visible for the class loader will be
                  searched for TLD-s.</p>
                </li>

                <li>
                  <p><code class="inline-code">MetaInfTldSources</code> and
                  <code class="inline-code">ClasspathTlds</code> can also be appended to or
                  replaced by the values of Java system properties
                  <code class="inline-code">org.freemarker.jsp.metaInfTldSources</code> and
                  <code class="inline-code">org.freemarker.jsp.classpathTlds</code>,
                  respectively. Thus one can adjust these in the Eclipse run
                  configuration without modifying the
                  <code class="inline-code">web.xml</code>. (See the <a href="http://freemarker.org/docs/api/freemarker/ext/servlet/FreemarkerServlet.html">Java
                  API documentation of
                  <code>FreemarkerServlet</code></a> for
                  more.)</p>
                </li>

                <li>
                  <p><code class="inline-code">FreemarkerServlet</code> now recognizes
                  the
                  <code class="inline-code">org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</code>
                  servlet context attribute, and adds entries to
                  <code class="inline-code">MetaInfTldSources</code> (introduced above) from
                  it.</p>
                </li>

                <li>
                  <p>Added <code class="inline-code">protected
                  FreemarkerServlet.createTaglibFactory()</code> to allow
                  fine tuning the settings of the
                  <code class="inline-code">TaglibFactory</code>. It now have a few setters,
                  like <code class="inline-code">setObjectWrapper</code>,
                  <code class="inline-code">setMetaInfTldSource</code>, etc.</p>
                </li>

                <li>
                  <p>Added new servlet init-param,
                  <code class="inline-code">BufferSize</code>. This sets the buffer size via
                  <code class="inline-code">HTTPServletResponse.setBufferSize()</code> if
                  the response state still allows that, ignores it
                  otherwise.</p>
                </li>

                <li>
                  <p>The <code class="inline-code">TemplatePath</code> servlet init-param
                  now supports a new kind of path, that looks like
                  <code class="inline-code">classpath:com/example/myapp/templates</code>.
                  This is similar to the old
                  <code class="inline-code">class://com/example/myapp/templates</code>, but
                  it uses the Thread Context Class Loader of the thread that
                  initializes <code class="inline-code">FreemarkerSerlvet</code>, and thus
                  will work even if <code class="inline-code">freemarker.jar</code> is not
                  local to the web application. <code class="inline-code">class://</code>
                  has the problem that it uses the defining class loader of
                  <code class="inline-code">FreemarkerSerlvet</code> itself (or of its
                  subclass).</p>
                </li>

                <li>
                  <p>If <code class="inline-code">incompatible_improvements</code> is set
                  to 2.3.22 (or higher), the <code class="inline-code">TemplatePath</code>
                  servlet init-param supports specifying multiple comma
                  separated paths inside
                  <code class="inline-code">[<em class="code-color">...</em>]</code>, like
                  <code class="inline-code">&lt;param-value&gt;[ WEB-INF/templates,
                  classpath:com/example/myapp/templates
                  ]&lt;/param-value&gt;</code>. This internally creates a
                  <code class="inline-code">freemarker.cache.MultiTemplateLoader</code>.</p>
                </li>

                <li>
                  <p>Added new servlet <code class="inline-code">init-param</code>,
                  <code class="inline-code">ExceptionOnMissingTemplate</code>. Setting this
                  to <code class="inline-code">true</code> changes the behavior on
                  template-not-found errors to similar to what you experience
                  with other kind of template exceptions (a HTTP 500
                  "Internal Server error" response on most
                  setups). When it&#39;s <code class="inline-code">false</code> (the legacy
                  behavior), you only get a HTTP 404 "Not found".
                  While that&#39;s also how JSP views work, this turns out to be a
                  problem, because some frameworks give 404 to the visitor too
                  if the MVC view gives 404. But to get to the point where you
                  forward to the MVC View, the visitor had to visit a valid
                  URL, only that page misses its View, so its broken on the
                  server side, so it should be a 500.</p>
                </li>

                <li>
                  <p>Added new overridable method:
                  <code class="inline-code">FreemarkerServlet.createDefaultObjectWrapper()</code>.
                  This can be used for what
                  <code class="inline-code">createObjectWrapper()</code> is usually
                  overridden for, but without unwillingly disabling the
                  processing of the related init-params (like of
                  <code class="inline-code">object_wrapper</code>).</p>
                </li>

                <li>
                  <p>Improved (or fixed) error logging: Now logs will
                  always get into FreeMarker&#39;s own log, not only into the
                  servlet container log. Also, earlier template-not-found and
                  template parsing error details logs were sometimes lost,
                  depending on the servlet container.</p>
                </li>

                <li>
                  <p>Bug fixed, only active with
                  <code class="inline-code">incompatible_improvements</code> set to 2.3.22
                  (or higher): Some kind of values, when put into the JSP
                  <em>page</em> scope (via
                  <code class="inline-code">#global</code> or via the JSP
                  <code class="inline-code">PageContext</code> API) and later read back with
                  the JSP <code class="inline-code">PageContext</code> API (typically in a
                  custom JSP tag), might come back as FreeMarker
                  <code class="inline-code">TemplateModel</code> objects instead of as
                  objects with a standard Java type. Other Servlet scopes
                  aren&#39;t affected. It&#39;s highly unlikely that something expects
                  the presence of this bug. The affected values are of the FTL
                  types listed below, and to trigger the bug, they either had
                  to be created directly in the template (like as an FTL
                  literal or with
                  <code class="inline-code">?date</code>/<code class="inline-code">time</code>/<code class="inline-code">datetime</code>),
                  or you had to use <code class="inline-code">DefaultObjectWrapper</code> or
                  <code class="inline-code">SimpleObjectWrapper</code> (or a subclass of
                  them):</p>

                  <ul>
                    <li>
                      <p>FTL date/time/date-time values may came back as
                      <code class="inline-code">freemarker.template.SimpleDate</code>-s, now
                      they come back as <code class="inline-code">java.util.Date</code>-s
                      instead.</p>
                    </li>

                    <li>
                      <p>FTL sequence values may came back as
                      <code class="inline-code">SimpleSequence</code>-s, now they come back
                      as <code class="inline-code">java.util.List</code>-s as expected. This
                      stands assuming that the
                      <code class="inline-code">object_wrapper</code> configuration setting
                      is a subclass of <code class="inline-code">BeansWrapper</code> (such
                      as <code class="inline-code">DefaultObjectWrapper</code>), but that&#39;s
                      practically always the case in applications that use
                      FreeMarker&#39;s JSP extension (otherwise it can still work,
                      but it depends on the quality and capabilities of the
                      <code class="inline-code">ObjectWrapper</code> implementation).</p>
                    </li>

                    <li>
                      <p>FTL hash values may came back as
                      <code class="inline-code">SimpleHash</code>-es, now they come back as
                      <code class="inline-code">java.util.Map</code>-s as expected (again,
                      assuming that the object wrapper is a subclass of
                      <code class="inline-code">BeansWrapper</code>).</p>
                    </li>

                    <li>
                      <p>FTL collection values may came back as
                      <code class="inline-code">SimpleCollection</code>-s, now they come
                      back as <code class="inline-code">java.util.Collection</code>-s as
                      expected (again, assuming that the object wrapper is a
                      subclass of <code class="inline-code">BeansWrapper</code>).</p>
                    </li>
                  </ul>
                </li>

                <li>
                  <p>Bug fixed: Now <code class="inline-code">*.tld</code> files are
                  searched in <code class="inline-code">WEB-INF/</code> and in all its
                  subdirectories recursively. Earlier they were only searched
                  directly under <code class="inline-code">WEB-INF/</code> and
                  <code class="inline-code">WEB-INF/lib/</code>.</p>
                </li>

                <li>
                  <p>Bug fixed: Leading and trailing whitespace in TLD-s
                  inside the <code class="inline-code">name</code> and
                  <code class="inline-code">tag-class</code> elements is now removed.</p>
                </li>

                <li>
                  <p>Unwanted behavior fixed: In case multiple TLD-s map to
                  the same tag library URI, now
                  <code class="inline-code">WEB-INF/**/*.tld</code>-s has priority over
                  <code class="inline-code">META-INF/**/*.tld</code>-s coming from jar-s or
                  classpath directories. Earlier, it was the other way around,
                  except that <code class="inline-code">META-INF/lib/*.tld</code>-s could
                  still take precedence randomly. While the JSP specification
                  (2.2) explicitly states that the order is not defined and
                  shouldn&#39;t be relied upon, it&#39;s just logical that if someone
                  puts a TLD directly under <code class="inline-code">WEB-INF</code>, he
                  meant that to be used in that particular web application,
                  rather than the TLD-s coming from the dependency jars which
                  are often shared by multiple web applications.</p>
                </li>

                <li>
                  <p>Bug fixed: Defaults set in an overridden
                  <code class="inline-code">FreemarkerServlet.createConfiguration</code>
                  won&#39;t be accidentally overwritten by
                  <code class="inline-code">FreemarkerServlet</code>&#39;s factory defaults
                  anymore. This was a problem with theses settings only:
                  <code class="inline-code">template_exception_handler</code>,
                  <code class="inline-code">log_template_exceptions</code>,
                  <code class="inline-code">object_wrapper</code>,
                  <code class="inline-code">template_loader</code>.</p>
                </li>

                <li>
                  <p>Bug fixed: If you had multiple
                  <code class="inline-code">FreemarkerServlet</code>-s with different
                  configuration settings in the same servlet context, that
                  could lead to malfunction. (Normally, you only have one,
                  just like there&#39;s only one servlet that processes
                  <code class="inline-code">*.jsp</code>.)</p>
                </li>

                <li>
                  <p>Removed all the <code class="inline-code">xsd</code> files
                  (<code class="inline-code">web-app</code> and <code class="inline-code">taglib</code>
                  schemas) from the FreeMarker artifact and from the XML
                  entity resolver, as they were unused during XML
                  parsing.</p>
                </li>

                <li>
                  <p>Generally improved implementation quality
                  (maintainability, error messages, performance bug fixes,
                  test coverage) and better API documentation.</p>
                </li>
              </ul>
            </li>

            <li>
              <p>Logging facility improvements:</p>

              <ul>
                <li>
                  <p>Just like earlier, when auto-selecting the logger
                  library (the default behavior), FreeMarker choses Log4j if
                  it&#39;s available. But now, if that turns out to be
                  <code class="inline-code">log4j-over-slf4j</code>, FreeMarker will use
                  SLF4J directly instead. (This fixes the issue where the
                  logged location points to FreeMarker&#39;s log adapter class
                  instead of the real call place.)</p>
                </li>

                <li>
                  <p>FreeMarker now recognizes the
                  <code class="inline-code">org.freemarker.loggerLibrary</code> system
                  property, which specifies which logger to use, like
                  <code class="inline-code">java <em class="code-color">...</em>
                  -Dorg.freemarker.loggerLibrary=SLF4J</code>. This option
                  deprecates
                  <code class="inline-code">Logger.selectLoggerLibrary(int)</code> as that
                  was inherently unreliable (because you usually can&#39;t control
                  class initialization order very well). The system property
                  has precedence over
                  <code class="inline-code">Logger.selectLoggerLibrary</code>.</p>
                </li>

                <li>
                  <p>Generally improved implementation quality (more info
                  printed when something fails, etc.).</p>
                </li>

                <li>
                  <p>New configuration setting:
                  <code class="inline-code">log_template_exceptions</code>
                  (<code class="inline-code">Configuration.setLogTemplateExceptions(boolean)</code>).
                  This specifies if <code class="inline-code">TemplateException</code>-s
                  thrown by template processing are logged by FreeMarker or
                  not. The default is <code class="inline-code">true</code> for backward
                  compatibility, but that results in logging the exception
                  twice in properly written applications, because there the
                  <code class="inline-code">TemplateException</code> thrown by the public
                  FreeMarker API is also logged by the caller (even if only as
                  the cause exception of a higher level exception). Hence, in
                  modern applications it should be set to
                  <code class="inline-code">false</code>. (Note that this setting has no
                  effect on the logging of exceptions caught by
                  <code class="inline-code">#attempt</code>/<code class="inline-code">#recover</code>;
                  those are always logged.)</p>
                </li>
              </ul>
            </li>

            <li>
              <p><code class="inline-code">Environment</code> and custom directive
              related improvements:</p>

              <ul>
                <li>
                  <p>Added
                  <code class="inline-code">Environment.getCurrentDirectiveCallPlace()</code>,
                  which returns a <code class="inline-code">DirectiveCallPlace</code> object
                  when called from a custom directive (i.e., from
                  <code class="inline-code">TemplateDirectiveModel.execute()</code>). The
                  <code class="inline-code">DirectiveCallPlace</code> objects lets you
                  associate an arbitrary object to the directive invocation
                  inside the template, which can be used for call-place-bound
                  caching (like the minification of non-dynamic nested
                  content). See <code class="inline-code">DirectiveCallPlace</code> in the
                  Java API documentation for more.</p>
                </li>

                <li>
                  <p>Added
                  <code class="inline-code">Environment.getMainTemplate()</code>. Deprecated
                  the ambiguous (and often broken: [<a href="https://sourceforge.net/p/freemarker/bugs/145/">145</a>])
                  <code class="inline-code">Environment.getTemplate()</code>.</p>
                </li>
              </ul>
            </li>

            <li>
              <p>Template loading:</p>

              <ul>
                <li>
                  <p>Added new <code class="inline-code">Configuration</code> setting,
                  <code class="inline-code">template_lookup_strategy</code>
                  (<code class="inline-code">Configuration.setTemplateLookupStrategy(TemplateLookupStrategy)</code>).
                  This allows customizing what
                  <code class="inline-code">TemplateLoader</code>-level names will be tried
                  when a template is requested. With this you can, for
                  example, define a custom localized lookup sequence instead
                  of the default (which looks like:
                  <code class="inline-code">foo_de_LU_MAC.ftl, foo_de_LU.ftl,
                  foo_de.ftl,</code><code class="inline-code"> foo.ftl</code>).</p>
                </li>

                <li>
                  <p>Added new
                  <code class="inline-code">Configuration.getTemplate(<em class="code-color">...</em>)</code>
                  parameter, <code class="inline-code">Object customLookupCondition</code>.
                  This parameter can be used by custom a
                  <code class="inline-code">TemplateLookupStrategy</code> to deduce the
                  actual template name(s) from the requested name (similarly
                  to as the default lookup strategy does that based on the
                  locale). For example, on a multi-domain Web site, one may
                  want to define some templates that are specialized to a
                  domain, and thus use the domain name as the custom lookup
                  condition. Then, when <code class="inline-code">foo.ftl</code> is
                  requested, a custom
                  <code class="inline-code">TemplateLookupStrategy</code> could first look
                  for <code class="inline-code">@somedomain.com/foo.ftl</code>, and then for
                  <code class="inline-code">@default/foo.ftl</code>. See the JavaDoc of the
                  relevant
                  <code class="inline-code">Configuration.getTemplate(<em class="code-color">...</em>)</code>
                  overload for more details; note there the requirements
                  regarding the <code class="inline-code">hashCode</code> and
                  <code class="inline-code">equals</code> of the
                  <code class="inline-code">customLookupCondition</code>.</p>
                </li>

                <li>
                  <p>Added new <code class="inline-code">Configuration</code> setting,
                  <code class="inline-code">template_name_format</code>
                  (<code class="inline-code">Configuration.setTemplateNameFormat(TemplateNameFormat)</code>).
                  This allows specifying the naming rules used by FreeMarker.
                  For now, custom implementations aren&#39;t allowed, and you can
                  only chose between
                  <code class="inline-code">TemplateNameFormat.DEFAULT_2_3_0</code> (the
                  default) and <code class="inline-code">DEFAULT_2_4_0</code> (recommended,
                  at least for new projects). <code class="inline-code">DEFAULT_2_4_0</code>
                  has several advantages, but isn&#39;t fully backward compatible
                  (though most applications won&#39;t be affected). For typical
                  mistakes like using backslash instead of slash, or backing
                  out of the root, it gives
                  <code class="inline-code">MalformedTemplateNameFormatException</code>
                  instead of <code class="inline-code">TempalteNotFoundException</code>. It
                  allows scheme names to be terminated with
                  <code class="inline-code">:</code> alone, instead of a
                  <code class="inline-code">://</code> (which is also supported), like in
                  <code class="inline-code">classpath:foo/bar.ftl</code>. It fixes numerous
                  legacy glitches (bugs), mostly related to the interpretation
                  of <code class="inline-code">..</code> after special steps like
                  <code class="inline-code">.</code> or <code class="inline-code">*</code>. See the full
                  list of differences in the <a href="http://freemarker.org/docs/api/freemarker/cache/TemplateNameFormat.html#DEFAULT_2_4_0">Java
                  API documentation of
                  <code>TemplateNameFormat.DEFAULT_2_4_0</code></a>.</p>
                </li>

                <li>
                  <p><code class="inline-code">ClassTemplateLoader</code> now can be
                  created by specifying a <code class="inline-code">ClassLoader</code>
                  directly, rather than by specifying a base
                  <code class="inline-code">Class</code>. That is, now there&#39;s
                  <code class="inline-code">ClassTemplateLoader(ClassLoader, String)</code>
                  constructor, and also a
                  <code class="inline-code">Configuration.setClassLoaderForTemplateLoading(ClassLoader,
                  String)</code> method.</p>
                </li>

                <li>
                  <p>Added new exception,
                  <code class="inline-code">TemplateNotFoundException</code>, which is now
                  used instead of <code class="inline-code">TemplateNotFoundException</code>
                  when getting a template. As it extends
                  <code class="inline-code">TemplateNotFoundException</code>, this change is
                  backward compatible. The main goal was to counter the common
                  misunderstanding that template paths are real file paths.
                  However, the new exception also has the benefit that it can
                  give additional FreeMarker-specific information about the
                  error, like right now it has
                  <code class="inline-code">getTemplateName()</code> and
                  <code class="inline-code">getCustomLookupCondition()</code>
                  methods.</p>
                </li>

                <li>
                  <p><code class="inline-code">Template</code>-s now have a
                  <code class="inline-code">getSourceName()</code> method, in additionally
                  to <code class="inline-code">getName()</code>. These two return the same
                  as far as no localized lookup or acquisition
                  (<code class="inline-code">*</code> in the name) or other lookup strategy
                  was actively involved. But when it was,
                  <code class="inline-code">getSourceName()</code> gives the name with which
                  the template was actually loaded from the
                  <code class="inline-code">TemplateLoader</code>, while
                  <code class="inline-code">getName()</code> returns (and had always
                  returned) the name with which the template was requested (in
                  canonicalized form). <code class="inline-code">getName()</code> is used
                  for everything (like for relative inclusion resolution),
                  except for location information in error messages, which now
                  uses <code class="inline-code">getSourceName()</code>. Also,
                  <code class="inline-code">TemplateException</code> now has a
                  <code class="inline-code">getSourceName()</code> method.</p>
                </li>

                <li>
                  <p><code class="inline-code">Configuration.getTemplate(<em class="code-color">...</em>)</code>
                  overloads now accept <code class="inline-code">null</code> for the
                  <code class="inline-code">locale</code> and <code class="inline-code">encoding</code>
                  parameters, in which case they use the same defaults as the
                  overloads where the parameter is omitted.</p>
                </li>

                <li>
                  <p>Debugger SPI implementators, attention: The
                  <code class="inline-code">DebugBreak</code> instruction will now send the
                  <code class="inline-code">sourceName</code> of the template to the
                  <code class="inline-code">suspendEnvironmentSpi</code> callback, rather
                  than its <code class="inline-code">name</code>. You should also use the
                  <code class="inline-code">sourceName</code> in
                  <code class="inline-code">registerTemplateSpi</code> and such, not the
                  <code class="inline-code">name</code>.</p>
                </li>
              </ul>
            </li>

            <li>
              <p>Configuration:</p>

              <ul>
                <li>
                  <p>Added
                  <code class="inline-code">Configuration.unset<em class="code-color">Xxx</em></code>
                  and
                  <code class="inline-code">is<em class="code-color">Xxx</em>ExplicitlySet</code>
                  methods for several settings. Unsetting a setting makes it
                  behave as if
                  <code class="inline-code">set<em class="code-color">Xxx</em></code> was
                  never called, thus the setting will use the default value
                  that fits the current
                  <code class="inline-code">incompatible_improvements</code> value and will
                  be adjusted as <code class="inline-code">incompatible_improvements</code>
                  is changed later.</p>
                </li>

                <li>
                  <p>When configuring FreeMarker from
                  <code class="inline-code">java.util.Properties</code> (or with
                  <code class="inline-code">String</code>-<code class="inline-code">String</code>
                  name-value pairs in general):</p>

                  <ul>
                    <li>
                      <p>The <code class="inline-code">default</code> setting value is
                      now recognized by
                      <code class="inline-code">template_exception_handler</code>,
                      <code class="inline-code">template_storage</code>,
                      <code class="inline-code">template_loader</code> (and by the new
                      <code class="inline-code">template_lookup_strategy</code> and
                      <code class="inline-code">template_name_format</code>) settings, and
                      it causes
                      <code class="inline-code">Configuration.unset<em class="code-color">Xxx</em>()</code>
                      to be called.</p>
                    </li>

                    <li>
                      <p>Bug fixed: When setting
                      <code class="inline-code">object_wrapper</code> to
                      <code class="inline-code">default</code> (as opposed to not specifying
                      it), it has ignored the
                      <code class="inline-code">incompatible_improvements</code> and has
                      always used
                      <code class="inline-code">ObjectWrapper.DEFAULT_WRAPPER</code>. This
                      fix only matters when
                      <code class="inline-code">incompatible_improvements</code> is exactly
                      2.3.21, as that&#39;s when the default object wrapper was
                      changed from
                      <code class="inline-code">ObjectWrapper.DEFAULT_WRAPPER</code> to the
                      result of <code class="inline-code">new
                      DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_21).build()</code>,
                      which is a bit different singleton, as it has read-only
                      configuration settings and bug fixed overloaded method
                      selection rules. To use
                      <code class="inline-code">ObjectWrapper.DEFAULT_WRAPPER</code>
                      regardless of the value of the
                      <code class="inline-code">incompatible_improvements</code> setting,
                      use the new <code class="inline-code">default_2_3_0</code>
                      value.</p>
                    </li>
                  </ul>
                </li>

                <li>
                  <p>Bug fixed: Changing the value of the
                  <code class="inline-code">localized_lookup</code> setting now empties the
                  template cache, so that old lookup results won&#39;t be reused.
                  (This of course only matters if you change this setting
                  under an already running service, which is very
                  unlikely.)</p>
                </li>
              </ul>
            </li>

            <li>
              <p>Miscellaneous:</p>

              <ul>
                <li>
                  <p>Bug fixed [<a href="https://sourceforge.net/p/freemarker/bugs/145/">145</a>],
                  active only with
                  <code class="inline-code">incompatible_improvements</code> set to 2.3.22
                  (or higher): <code class="inline-code">#include</code> and
                  <code class="inline-code">#nested</code> doesn&#39;t change the parent
                  <code class="inline-code">Template</code> (see
                  <code class="inline-code">Configurable.getParent()</code>) of the
                  <code class="inline-code">Environment</code> anymore to the
                  <code class="inline-code">Template</code> that&#39;s included or where
                  <code class="inline-code">#nested</code> "returns" to. Thus,
                  the parent of <code class="inline-code">Environment</code> will be now
                  always the main <code class="inline-code">Template</code>. (The main
                  <code class="inline-code">Template</code> is the
                  <code class="inline-code">Template</code> whose <code class="inline-code">process</code>
                  or <code class="inline-code">createProcessingEnvironment</code> method was
                  called to initiate the output generation.) Note that this
                  only matters if you have set settings directly on
                  <code class="inline-code">Template</code> objects (not to be confused with
                  setting settings in templates via
                  <code class="inline-code">#setting</code>, which just modifies the
                  <code class="inline-code">Environment</code>, and so isn&#39;t affected by
                  this fix), and almost nobody does that. Also note that macro
                  calls have never changed the <code class="inline-code">Environment</code>
                  parent to the <code class="inline-code">Template</code> that contains the
                  macro definition, so there&#39;s no change there now.</p>
                </li>

                <li>
                  <p>Bug fixed [<a href="https://sourceforge.net/p/freemarker/bugs/419/">419</a>]:
                  FreeMarker doesn&#39;t fail anymore when it has no permission to
                  read Java system properties, like when used in unsigned
                  applets. It just logs some warnings.</p>
                </li>

                <li>
                  <p><code class="inline-code">HTML_DEBUG</code> and
                  <code class="inline-code">DEBUG</code>
                  <code class="inline-code">TemplateExceptionHandler</code> output now
                  contains a warning like "HTML_DEBUG mode; use RETHROW
                  in production!", due to frequent misuse.</p>
                </li>

                <li>
                  <p>Some fixes and improvements in template canonical form
                  output, and as a consequence of that, in FTL stack trace
                  instruction displaying.</p>
                </li>

                <li>
                  <p>Marked some historically public but otherwise internal
                  API-s as deprecated, so that the disclaimer is more apparent
                  in IDE-s.</p>
                </li>
              </ul>
            </li>
          </ul>
        
          



<h2 class="content-header header-section2" id="autoid_150">Notes</h2>


          <p><a name="topic.defaultObjectWrapperSwitchToAdapters"></a>The
          consequences and reasons of introducing adapter approach for
          container types in <code class="inline-code">DefaultObjectWrapper</code> when its
          incompatibleImprovements is set to 2.3.22:</p>

          <ul>
            <li>
              <p>With the new approach (the adapter approach), the key
              order of <code class="inline-code">Map</code>-s is never lost. The copying
              approach could only keep that for <code class="inline-code">HashMap</code>
              subclasses (such as <code class="inline-code">LinkedHashMap</code>) and
              <code class="inline-code">SortedMap</code>-s (such as
              <code class="inline-code">TreeMap</code>), but not for more exotic
              <code class="inline-code">Map</code>-s, like Guava&#39;s
              <code class="inline-code">ImmutableMap</code>. Also, any other behavioral
              peculiarities of the original <code class="inline-code">Map</code> (e.g., case
              insensitive key lookup) is kept now.</p>
            </li>

            <li>
              <p>The exact type and identity of the
              <code class="inline-code">Map</code>/<code class="inline-code">List</code> is kept when the
              wrapped value is passed back to a Java method from the template.
              With the legacy approach the Java methods have received a
              <code class="inline-code">Map</code> or <code class="inline-code">List</code> of a special
              FreeMarker specific type (that acted as an adapter for the
              <code class="inline-code">TemplateModel</code>).</p>
            </li>

            <li>
              <p>Performance characteristics change, mostly for the better,
              but it depends on the application. If the template reads the
              <em>same(!)</em> entry <em>from the data
              model</em> roughly once or twice (or not at all), which is
              typical, them the adapter approach gives better results,
              otherwise the legacy copying approach is faster (as it can reuse
              the wrapped entry from the previous read), though this slowdown
              certainly not a concern for most applications. The performance
              of the new adapter approach is more predictable, because it has
              no initial "spike" to set up the container copy
              (especially painful for huge collections), instead the
              performance is linearly proportional to the number of data model
              reads (and not to the number of collection entries).</p>
            </li>

            <li>
              <p>If the
              <code class="inline-code">Map</code>/<code class="inline-code">List</code>/array is changed
              after it was wrapped, the change will now become visible in the
              data-model. With the copying approach, the wrapped value was a
              shallow-snapshot of the original
              <code class="inline-code">Map</code>/<code class="inline-code">List</code>/array. While it&#39;s
              unlikely that someone has deliberately utilized this, it&#39;s a
              risk factor when switching to adapters.</p>
            </li>

            <li>
              <p>It&#39;s theoretically possible that some code (mostly
              <code class="inline-code">TemplateDirectiveModel</code> implementations)
              mistakenly assumed that wrapped <code class="inline-code">Map</code>-s are
              <code class="inline-code">SimpleHash</code>-es, and wrapped
              <code class="inline-code">List</code>-s are
              <code class="inline-code">SimpleSequence</code>-s, etc., instead of them just
              being <code class="inline-code">TemplateHashModel</code>-s and
              <code class="inline-code">TemplateSequenceModel</code>-s. Such code was always
              wrong, but now it will indeed break, so it&#39;s a risk
              factor.</p>
            </li>

            <li>
              <p>As now the exact type of the wrapped original object is
              used for overloaded method selection, the choice can be
              different (and similar to what it would be with pure
              <code class="inline-code">BeansWrapper</code>). It&#39;s difficult to find cases
              where this matters. A change is most probable around arrays, as
              with the copying approach they were unwrapped to
              <code class="inline-code">List</code>-s, not to the original array. As the
              overloaded method mechanism can convert between arrays and lists
              (in both directions), it&#39;s usually not a problem. But, it
              doesn&#39;t do conversion between different array types when the
              overloaded method has various types on the parameter position of
              the array, so that&#39;s a risk factor.</p>
            </li>

            <li>
              <p><code class="inline-code">SimpleHash</code> and
              <code class="inline-code">SimpleSequence</code> haven&#39;t become deprecated.
              They are still used for hashes and sequences created in FTL, and
              are recommended for values that are built specifically to be
              used from templates, rather than wrapping an already existing
              <code class="inline-code">Map</code> or <code class="inline-code">List</code> or
              array.</p>
            </li>

            <li>
              <p><code class="inline-code">List</code>-s and <code class="inline-code">Map</code>-s
              that are exposed to templates in multiple threads are now under
              greater stress regarding their correct operation under
              multi-threaded read-only access. This is because the adapters
              won&#39;t copy their contents into well known
              <code class="inline-code">List</code> and <code class="inline-code">Map</code>
              implementations (<code class="inline-code">HashMap</code>,
              <code class="inline-code">ArrayList</code>, etc.) before accessing them from
              multiple threads. So this is mostly a concern with custom
              <code class="inline-code">List</code> and <code class="inline-code">Map</code>
              implementations, which aren&#39;t as mature as the standard Java
              classes. Note that this was always like so with pure
              <code class="inline-code">BeansWrapper</code>, which is used by a lot of
              projects/frameworks (like by Struts) for a long time, so it&#39;s
              not an uncharted territory.</p>
            </li>

            <li>
              <p>When the wrapped <code class="inline-code">List</code> is a
              <code class="inline-code">AbstractSequentialList</code> (like a
              <code class="inline-code">LinkedList</code>), the resulting adapter will
              implement <code class="inline-code">TemplateCollectionModel</code> for more
              efficient enumeration (<code class="inline-code">#list</code>-ing), in
              additionally to <code class="inline-code">TemplateSequenceModel</code> of
              course. <code class="inline-code">TemplateCollectionModel</code> allows FTL to
              traverse the list without accessing elements by index. With the
              legacy copying approach
              <code class="inline-code">TemplateCollectionModel</code> wasn&#39;t implemented as
              it wasn&#39;t needed for efficient enumeration there.</p>
            </li>

            <li>
              <p>Iterators (when you put them directly into the data-model)
              are wrapped into <code class="inline-code">DefaultIteratorAdapter</code>
              instead of <code class="inline-code">SimpleCollection</code>. This has two
              consequences:</p>

              <ul>
                <li>
                  <p>The wrapped <code class="inline-code">Iterator</code> is now
                  unwrapped properly to the original Java object when it&#39;s
                  passed to Java method from the template.</p>
                </li>

                <li>
                  <p>Wrapped <code class="inline-code">Iterator</code>-s (not to be
                  confused with <code class="inline-code">Iterable</code>) aren&#39;t
                  thread-safe anymore, to spare some synchronizations, after
                  all, exposing the same <code class="inline-code">Iterator</code> to
                  multiple parallel template executions doesn&#39;t make much
                  sense. This shouldn&#39;t be a migration concern, as even
                  earlier, only one of those template executions could succeed
                  (the "content" of <code class="inline-code">Iterator</code>-s
                  wasn&#39;t copied, so the one who first accessed it become the
                  exclusive owner). The change is just that earlier it was
                  guaranteed that the other threads will fail (that was the
                  thread-safe about it), while now there are no such
                  guarantees.</p>
                </li>
              </ul>
            </li>
          </ul>
        <div class="bottom-pagers-wrapper"><div class="pagers bottom"><a class="paging-arrow previous" href="versions_2_3_23.html"><span>Previous</span></a><a class="paging-arrow next" href="versions_2_3_21.html"><span>Next</span></a></div></div></div></div>      </div>
    </div>
<div class="site-footer"><div class="site-width"><div class="footer-top"><div class="col-left sitemap"><div class="column"><h3 class="column-header">Overview</h3><ul><li><a href="http://freemarker.org/index.html">What is FreeMarker?</a></li><li><a href="http://freemarker.org/freemarkerdownload.html">Download</a></li><li><a href="app_versions.html">Version history</a></li><li><a href="http://freemarker.org/history.html">About us</a></li><li><a itemprop="license" href="app_license.html">License</a></li></ul></div><div class="column"><h3 class="column-header">Handy stuff</h3><ul><li><a href="http://freemarker-online.kenshoo.com/">Try template online</a></li><li><a href="dgui_template_exp.html#exp_cheatsheet">Expressions cheatsheet</a></li><li><a href="ref_directive_alphaidx.html">#directives</a></li><li><a href="ref_builtins_alphaidx.html">?built_ins</a></li><li><a href="ref_specvar.html">.special_vars</a></li></ul></div><div class="column"><h3 class="column-header">Community</h3><ul><li><a href="https://github.com/nanlei/freemarker/tree/manual-zh-2.3-gae/src/manual">Chinese Manual on Github</a></li><li><a href="https://github.com/freemarker/freemarker">FreeMarker on Github</a></li><li><a href="https://twitter.com/freemarker">Follow us on Twitter</a></li><li><a href="https://sourceforge.net/p/freemarker/bugs/new/">Report a bug</a></li><li><a href="http://stackoverflow.com/questions/ask?tags=freemarker">Ask a question</a></li><li><a href="http://freemarker.org/mailing-lists.html">Mailing lists</a></li></ul></div></div><div class="col-right"><ul class="social-icons"><li><a class="github" href="https://github.com/freemarker/freemarker">Github</a></li><li><a class="twitter" href="https://twitter.com/freemarker">Twitter</a></li><li><a class="stack-overflow" href="http://stackoverflow.com/questions/ask?tags=freemarker">Stack Overflow</a></li></ul><a class="xxe" href="http://www.xmlmind.com/xmleditor/" rel="nofollow" title="Edited with XMLMind XML Editor"><span>Edited with XMLMind XML Editor</span></a></div></div><div class="footer-bottom"><p><span class="generated-for-product">Generated for: Freemarker 2.3.23</span><span class="last-updated"> Last generated:
<time itemprop="dateModified" datetime="2015-09-18T14:38:51Z" title="Friday, September 18, 2015 2:38:51 PM GMT">2015-09-18 14:38:51 GMT</time></span></p> <p class="copyright">
© <span itemprop="copyrightYear">1999</span>–2015
<a itemtype="http://schema.org/Organization" itemprop="copyrightHolder" href="http://freemarker.org">The FreeMarker Project</a>. All rights reserved. </p>
</div></div></div></body>
</html>
